Network visualization using output from text model
Data preparation
edgelist <- read.csv("../../../Data/Text_Model_Data/edgelist.csv")
edgelist
Indicator title
indicator_info <- read.csv("../../../Data/Text_Model_Data/indicator_att.csv")
library(stringr)
str_replace_all(indicator_info$Indicator, fixed(" "), "")
Textdata <- datatable(indicator_info, rownames=TRUE, caption=htmltools::tags$caption(style="caption-side: bottom; text-align: center;", "Innovative counties in the U.S."), filter="top", extensions="Buttons", options=list(dom = "Bfrtip", buttons = c("colvis", "copy", "csv", "excel", "pdf", "print")))
Textdata
For future classification of indicators into the goals they belong to, create the nodes dataframe:
nodes <- edgelist %>%
select(indicator, related_indicator)
nodes <- data.frame(Indicator = unlist(nodes, use.names = FALSE))
nodes <- distinct(nodes)
str_replace_all(nodes$Indicator, fixed(" "), "")
[1] "1.1.1" "1.2.2" "1.3.1" "1.4.1" "1.4.2" "1.5.1" "1.5.2" "1.5.3" "1.5.4" "1.a.1" "1.a.2" "2.2.1"
[13] "2.2.2" "2.2.3" "2.3.1" "2.3.2" "2.4.1" "2.5.1" "2.5.2" "2.a.1" "2.a.2" "2.b.1" "2.c.1" "3.1.1"
[25] "3.2.1" "3.3.1" "3.3.2" "3.4.1" "3.4.2" "3.6.1" "3.7.2" "3.8.2" "3.9.2" "3.b.2" "4.1.1" "4.1.2"
[37] "4.2.1" "4.2.2" "4.3.1" "4.6.1" "4.7.1" "4.a.1" "4.b.1" "4.c.1" "5.2.1" "5.2.2" "5.3.1" "5.4.1"
[49] "5.6.1" "5.6.2" "5.a.1" "5.a.2" "5.b.1" "6.1.1" "6.3.2" "6.4.1" "6.4.2" "6.5.2" "6.6.1" "6.a.1"
[61] "6.b.1" "7.1.1" "7.2.1" "7.3.1" "7.a.1" "7.b.1" "8.1.1" "8.2.1" "8.3.1" "8.4.1" "8.4.2" "8.5.1"
[73] "8.6.1" "8.7.1" "8.8.2" "8.9.1" "8.a.1" "8.b.1" "9.2.1" "9.2.2" "9.3.1" "9.3.2" "9.4.1" "9.5.1"
[85] "9.5.2" "9.a.1" "9.b.1" "10.1.1" "10.3.1" "10.6.1" "10.7.1" "10.7.4" "10.a.1" "10.b.1" "11.1.1" "11.3.1"
[97] "11.3.2" "11.5.1" "11.5.2" "11.6.1" "11.7.2" "11.a.1" "11.b.1" "11.b.2" "12.1.1" "12.2.1" "12.4.1" "12.8.1"
[109] "13.1.2" "13.2.1" "13.2.2" "14.4.1" "14.5.1" "14.6.1" "14.7.1" "14.c.1" "15.1.1" "15.1.2" "15.4.1" "15.7.1"
[121] "15.9.1" "15.a.1" "16.1.1" "16.1.3" "16.2.1" "16.5.2" "16.6.1" "16.6.2" "16.8.1" "16.10.1" "16.10.2" "16.a.1"
[133] "17.1.1" "17.2.1" "17.4.1" "17.5.1" "17.10.1" "17.11.1" "17.15.1" "17.18.2" "17.18.3" "1.2.1" "1.b.1" "6.2.1"
[145] "11.2.1" "9.1.1" "3.8.1" "15.3.1" "16.b.1" "14.b.1" "13.1.1" "12.3.1" "13.1.3" "17.12.1" "17.9.1" "17.1.2"
[157] "11.4.1" "13.3.1" "12.c.1" "16.2.3" "15.6.1" "3.2.2" "3.3.3" "3.9.1" "3.9.3" "8.8.1" "5.3.2" "16.9.1"
[169] "5.5.2" "5.c.1" "9.c.1" "17.8.1" "12.a.1" "10.2.1" "17.3.2" "8.5.2" "12.2.2" "12.b.1" "10.4.1" "10.c.1"
[181] "16.1.2" "16.4.1" "17.19.2" "12.4.2" "17.14.1" "13.b.1" "13.a.1" "15.b.1" "17.16.1" "15.2.1" "15.4.2" "15.c.1"
[193] "16.3.1" "16.3.3" "16.7.2" "17.19.1"
#nodes$goal <- stri_match_first_regex(nodes$indicator, "(.*?)\\.")[,2]
#nodes$goal <-as.numeric(nodes$goal)
nodes<-merge(x=nodes,y=indicator_info,by="Indicator",all.x=TRUE)
g<-graph_from_data_frame(edgelist, directed=FALSE, vertices=nodes)
in_degree<-degree(g, mode="in")
in_degree<-as.data.frame(in_degree)
in_degree <- cbind(rownames(in_degree), in_degree)
rownames(in_degree) <- NULL
colnames(in_degree) <- c("Indicator","in_degree")
str_replace_all(in_degree$Indicator, fixed(" "), "")
[1] "1.1.1" "1.2.1" "1.2.2" "1.3.1" "1.4.1" "1.4.2" "1.5.1" "1.5.2" "1.5.3" "1.5.4" "1.a.1" "1.a.2"
[13] "1.b.1" "10.1.1" "10.2.1" "10.3.1" "10.4.1" "10.6.1" "10.7.1" "10.7.4" "10.a.1" "10.b.1" "10.c.1" "11.1.1"
[25] "11.2.1" "11.3.1" "11.3.2" "11.4.1" "11.5.1" "11.5.2" "11.6.1" "11.7.2" "11.a.1" "11.b.1" "11.b.2" "12.1.1"
[37] "12.2.1" "12.2.2" "12.3.1" "12.4.1" "12.4.2" "12.8.1" "12.a.1" "12.b.1" "12.c.1" "13.1.1" "13.1.2" "13.1.3"
[49] "13.2.1" "13.2.2" "13.3.1" "13.a.1" "13.b.1" "14.4.1" "14.5.1" "14.6.1" "14.7.1" "14.b.1" "14.c.1" "15.1.1"
[61] "15.1.2" "15.2.1" "15.3.1" "15.4.1" "15.4.2" "15.6.1" "15.7.1" "15.9.1" "15.a.1" "15.b.1" "15.c.1" "16.1.1"
[73] "16.1.2" "16.1.3" "16.10.1" "16.10.2" "16.2.1" "16.2.3" "16.3.1" "16.3.3" "16.4.1" "16.5.2" "16.6.1" "16.6.2"
[85] "16.7.2" "16.8.1" "16.9.1" "16.a.1" "16.b.1" "17.1.1" "17.1.2" "17.10.1" "17.11.1" "17.12.1" "17.14.1" "17.15.1"
[97] "17.16.1" "17.18.2" "17.18.3" "17.19.1" "17.19.2" "17.2.1" "17.3.2" "17.4.1" "17.5.1" "17.8.1" "17.9.1" "2.2.1"
[109] "2.2.2" "2.2.3" "2.3.1" "2.3.2" "2.4.1" "2.5.1" "2.5.2" "2.a.1" "2.a.2" "2.b.1" "2.c.1" "3.1.1"
[121] "3.2.1" "3.2.2" "3.3.1" "3.3.2" "3.3.3" "3.4.1" "3.4.2" "3.6.1" "3.7.2" "3.8.1" "3.8.2" "3.9.1"
[133] "3.9.2" "3.9.3" "3.b.2" "4.1.1" "4.1.2" "4.2.1" "4.2.2" "4.3.1" "4.6.1" "4.7.1" "4.a.1" "4.b.1"
[145] "4.c.1" "5.2.1" "5.2.2" "5.3.1" "5.3.2" "5.4.1" "5.5.2" "5.6.1" "5.6.2" "5.a.1" "5.a.2" "5.b.1"
[157] "5.c.1" "6.1.1" "6.2.1" "6.3.2" "6.4.1" "6.4.2" "6.5.2" "6.6.1" "6.a.1" "6.b.1" "7.1.1" "7.2.1"
[169] "7.3.1" "7.a.1" "7.b.1" "8.1.1" "8.2.1" "8.3.1" "8.4.1" "8.4.2" "8.5.1" "8.5.2" "8.6.1" "8.7.1"
[181] "8.8.1" "8.8.2" "8.9.1" "8.a.1" "8.b.1" "9.1.1" "9.2.1" "9.2.2" "9.3.1" "9.3.2" "9.4.1" "9.5.1"
[193] "9.5.2" "9.a.1" "9.b.1" "9.c.1"
nodes<-merge(x=nodes,y=in_degree,by="Indicator",all.x=TRUE)
nodes<-nodes %>%
select(Indicator, Goal, Indicator_title, in_degree)
nodes
Visualization
In the network graph below, the size of each vertices (each indicator) represents the number of related indicators that are connected to it. The width of the edges linking each indicator is determined according to the similarity score between each pair of related indicators. The indicators are grouped according to the goals they belong to, which are denoted by different colors of the vertices.
edges <- edgelist %>% dplyr::rename(Indicator = indicator)
nodes <- data.frame(id = nodes$Indicator,
label = nodes$Indicator,
group = nodes$Goal,
color = ifelse(nodes$Goal == 1,"#ea1d2d",ifelse(nodes$Goal == 2,"#d19f2a",ifelse(nodes$Goal == 3,"#2d9a47",
ifelse(nodes$Goal == 4,"#c22033",ifelse(nodes$Goal == 5,"#ef412a",ifelse(nodes$Goal == 6,"#00add8",
ifelse(nodes$Goal == 7,"#fdb714",ifelse(nodes$Goal == 8,"#8f1838",ifelse(nodes$Goal == 9,"#f36e24",
ifelse(nodes$Goal == 10,"#e01a83",ifelse(nodes$Goal == 11,"#f99d25",ifelse(nodes$Goal == 12,"#cd8b2a",
ifelse(nodes$Goal == 13,"#48773c",ifelse(nodes$Goal == 14,"#007dbb",ifelse(nodes$Goal == 15,"#40ae49",
ifelse(nodes$Goal == 16,"#00558a","#1a3668")))))))))))))))),
highlight = ifelse(nodes$Goal == 1,"#ea1d2d",ifelse(nodes$Goal == 2,"#d19f2a",ifelse(nodes$Goal == 3,"#2d9a47",
ifelse(nodes$Goal == 4,"#c22033",ifelse(nodes$Goal == 5,"#ef412a",ifelse(nodes$Goal == 6,"#00add8",
ifelse(nodes$Goal == 7,"#fdb714",ifelse(nodes$Goal == 8,"#8f1838",ifelse(nodes$Goal == 9,"#f36e24",
ifelse(nodes$Goal == 10,"#e01a83",ifelse(nodes$Goal == 11,"#f99d25",ifelse(nodes$Goal == 12,"#cd8b2a",
ifelse(nodes$Goal == 13,"#48773c",ifelse(nodes$Goal == 14,"#007dbb",ifelse(nodes$Goal == 15,"#40ae49",
ifelse(nodes$Goal == 16,"#00558a","#1a3668")))))))))))))))),
size = nodes$in_degree*10)
edges <- data.frame(from = edges$Indicator, to=edges$related_indicator, width = edges$similarity_score*4, color='gray')
nodes$shape <- "dot"
nodes$shadow <- FALSE
# this section doesn't allow our graph to show up - no idea why.
# nodes$color.background <- nodes$color
# nodes$color.border <- nodes$color
# nodes$color.highlight.background <- nodes$color
# nodes$color.highlight.border <- nodes$color
edges$color <- "gray" # line color
edges$smooth <- FALSE # should the edges be curved?
edges$shadow <- FALSE
visnet<-visNetwork(nodes,edges, height = "700px", width = "100%", main="Text Network Model",submain= "UN SDG Indicator Metadata", footer="Zoom in to see indicator name, click/hover to see indicator title") %>%
visEdges(smooth = FALSE) %>%
visOptions(selectedBy = "Goal",
highlightNearest = TRUE,
nodesIdSelection = TRUE) #%>%
#visLegend(main="Legend",position="right", ncol=1)
visnet
visSave(visnet, file = "Text Network Model.html")
Network visualization using output from the social network model
Indonesia
###Data preparation
edgelistindo <- read.csv("~/Documents/GitHub/G5055_Practicum_Project2/Data/PCA_results/indo_coefficients_sig.csv")
#Some preprocessing
edgelistindo<-edgelistindo%>%
select(Var1, Var2, value)%>%
filter(Var1!=Var2)
names(edgelistindo)<-c("from","to","value")
edgelistindo
For future classification of indicators into the goals they belong to, create the nodes dataframe:
indonodes <- edgelistindo %>%
select(from, to)
indonodes <- data.frame(Indicator = unlist(indonodes, use.names = FALSE))
indonodes <- distinct(indonodes)
#indonodes$goal <- stri_match_first_regex(indonodes$indicator, "(.*?)\\.")[,2]
#indonodes$goal <-as.numeric(indonodes$goal)
indonodes<-merge(x=indonodes,y=indicator_info,by="Indicator",all.x=TRUE)
g2<-graph_from_data_frame(edgelistindo, directed=FALSE, vertices=indonodes)
in_degree<-degree(g2, mode="in")
in_degree<-as.data.frame(in_degree)
in_degree <- cbind(rownames(in_degree), in_degree)
rownames(in_degree) <- NULL
colnames(in_degree) <- c("Indicator","in_degree")
indonodes<-merge(x=indonodes,y=in_degree,by="Indicator",all.x=TRUE)
indonodes<-indonodes %>%
arrange(Goal)
indonodes<-indonodes %>%
select(Indicator, Goal, Indicator_title, in_degree)
indonodes
indonodes
Visualization
indicator_info <- read.csv("../../../Data/Text_Model_Data/indicator_att.csv")
library(stringr)
str_replace_all(indicator_info$Indicator, fixed(" "), "")
[1] "1.1.1" "1.2.1" "1.2.2" "1.3.1" "1.4.1" "1.4.2" "1.5.1" "1.5.2" "1.5.3" "1.5.4" "1.a.1" "1.a.2"
[13] "1.b.1" "2.1.1" "2.1.2" "2.2.1" "2.2.2" "2.2.3" "2.3.1" "2.3.2" "2.4.1" "2.5.1" "2.5.2" "2.a.1"
[25] "2.a.2" "2.b.1" "2.c.1" "3.1.1" "3.1.2" "3.2.1" "3.2.2" "3.3.1" "3.3.2" "3.3.3" "3.3.4" "3.3.5"
[37] "3.4.1" "3.4.2" "3.5.1" "3.5.2" "3.6.1" "3.7.1" "3.7.2" "3.8.1" "3.8.2" "3.9.1" "3.9.2" "3.9.3"
[49] "3.a.1" "3.b.1" "3.b.2" "3.b.3" "3.c.1" "3.d.1" "3.d.2" "4.1.1" "4.1.2" "4.2.1" "4.2.2" "4.3.1"
[61] "4.4.1" "4.5.1" "4.6.1" "4.7.1" "4.a.1" "4.b.1" "4.c.1" "5.1.1" "5.2.1" "5.2.2" "5.3.1" "5.3.2"
[73] "5.4.1" "5.5.1" "5.5.2" "5.6.1" "5.6.2" "5.a.1" "5.a.2" "5.b.1" "5.c.1" "6.1.1" "6.2.1" "6.3.1"
[85] "6.3.2" "6.4.1" "6.4.2" "6.5.1" "6.5.2" "6.6.1" "6.a.1" "6.b.1" "7.1.1" "7.1.2" "7.2.1" "7.3.1"
[97] "7.a.1" "7.b.1" "8.1.1" "8.2.1" "8.3.1" "8.4.1" "8.4.2" "8.5.1" "8.5.2" "8.6.1" "8.7.1" "8.8.1"
[109] "8.8.2" "8.9.1" "8.10.1" "8.10.2" "8.a.1" "8.b.1" "9.1.1" "9.1.2" "9.2.1" "9.2.2" "9.3.1" "9.3.2"
[121] "9.4.1" "9.5.1" "9.5.2" "9.a.1" "9.b.1" "9.c.1" "10.1.1" "10.2.1" "10.3.1" "10.4.1" "10.4.2" "10.5.1"
[133] "10.6.1" "10.7.1" "10.7.2" "10.7.3" "10.7.4" "10.a.1" "10.b.1" "10.c.1" "11.1.1" "11.2.1" "11.3.1" "11.3.2"
[145] "11.4.1" "11.5.1" "11.5.2" "11.6.1" "11.6.2" "11.7.1" "11.7.2" "11.a.1" "11.b.1" "11.b.2" "12.1.1" "12.2.1"
[157] "12.2.2" "12.3.1" "12.4.1" "12.4.2" "12.5.1" "12.6.1" "12.7.1" "12.8.1" "12.a.1" "12.b.1" "12.c.1" "13.1.1"
[169] "13.1.2" "13.1.3" "13.2.1" "13.2.2" "13.3.1" "13.a.1" "13.b.1" "14.1.1" "14.2.1" "14.3.1" "14.4.1" "14.5.1"
[181] "14.6.1" "14.7.1" "14.a.1" "14.b.1" "14.c.1" "15.1.1" "15.1.2" "15.2.1" "15.3.1" "15.4.1" "15.4.2" "15.5.1"
[193] "15.6.1" "15.7.1" "15.8.1" "15.9.1" "15.a.1" "15.b.1" "15.c.1" "16.1.1" "16.1.2" "16.1.3" "16.1.4" "16.2.1"
[205] "16.2.2" "16.2.3" "16.3.1" "16.3.2" "16.3.3" "16.4.1" "16.4.2" "16.5.1" "16.5.2" "16.6.1" "16.6.2" "16.7.1"
[217] "16.7.2" "16.8.1" "16.9.1" "16.10.1" "16.10.2" "16.a.1" "16.b.1" "17.1.1" "17.1.2" "17.2.1" "17.3.1" "17.3.2"
[229] "17.4.1" "17.5.1" "17.6.1" "17.7.1" "17.8.1" "17.9.1" "17.10.1" "17.11.1" "17.12.1" "17.13.1" "17.14.1" "17.15.1"
[241] "17.16.1" "17.17.1" "17.18.2" "17.18.3" "17.19.1" "17.19.2"
Textdata <- datatable(indicator_info, rownames=TRUE, caption=htmltools::tags$caption(style="caption-side: bottom; text-align: center;", "Innovative counties in the U.S."), filter="top", extensions="Buttons", options=list(dom = "Bfrtip", buttons = c("colvis", "copy", "csv", "excel", "pdf", "print")))
Textdata
Guatemala (Not finished)
Data preparation
edgelistguate <- read.csv("~/Documents/GitHub/G5055_Practicum_Project2/Data/PCA_results/gua_coefficients_sig.csv")
#Some preprocessing
edgelistguate<-edgelistguate%>%
select(Var1, Var2, value)%>%
filter(Var1!=Var2)
names(edgelistindo)<-c("from","to","value")
edgelistguate
Visualization
guatenodes <- edgelistguate %>%
select(Var1, Var2)
guatenodes <- data.frame(indicatorname = unlist(guatenodes, use.names = FALSE))
guatenodes <- distinct(guatenodes)
#guatenodes$goal <- stri_match_first_regex(guatenodes$indicator, "(.*?)\\.")[,2]
#guatenodes$goal <-as.numeric(guatenodes$goal)
g3<-graph_from_data_frame(edgelistguate, directed=FALSE, vertices=guatenodes)
guatenodes
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKLS0tCnRpdGxlOiAiSW50ZXJhY3RpdmUgTmV0d29ya3MiCmF1dGhvcjogIkxpIFBlaXNoYW4iCmRhdGU6ICIxMS8yMy8yMDIxIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0aGVtZTogam91cm5hbAotLS0KPHN0eWxlPgpib2R5eyAvKiBOb3JtYWwgKi8KZm9udC1zaXplOiAxNXB4Owpjb2xvcjogYmxhY2s7Cn0Kd3JpdGUgeyAgCmxpbmUtaGVpZ2h0OiA3ZW07Cn0KdGFibGUgeyAvKiBUYWJsZSAqLwpmb250LXNpemU6IDEycHg7Cn0KaDEgeyAvKiBIZWFkZXIgMSAqLwpmb250LXNpemU6IDMwcHg7Cn0KaDIgeyAvKiBIZWFkZXIgMiAqCmZvbnQtc2l6ZTogMjZweDsKfQpoMyB7IC8qIEhlYWRlciAzICovCmZvbnQtc2l6ZTogMjJweDsKfQpjb2RlLnJ7IC8qIENvZGUgYmxvY2sgKi8KZm9udC1zaXplOiAxNHB4Owp9CnByZSB7IC8qIENvZGUgYmxvY2sgKi8KZm9udC1zaXplOiAxNHB4Cn0KLm1haW4tY29udGFpbmVyIHsKICAgIHdpZHRoOiA4MCU7CiAgICBtYXgtd2lkdGg6IHVuc2V0Owp9Cjwvc3R5bGU+CgpgYGB7ciBzZXR1cCwgZWNobz1GQUxTRSwgZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQpgYGAKCmBgYHtyIGxvYWQgcGFja2FnZXMsIGVjaG89RkFMU0UsIGV2YWw9VFJVRX0KbGlicmFyeShyZWFkeGwpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikgICAgCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHRleHRkYXRhKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHF1YW50ZWRhKQpsaWJyYXJ5KHJ2ZXN0KQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoU25vd2JhbGxDKQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShwbG90cml4KQpsaWJyYXJ5KHFkYXBEaWN0aW9uYXJpZXMpCmxpYnJhcnkoZm9ybWF0dGFibGUpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShEVCkKbGlicmFyeShuZXR3b3JrKQpsaWJyYXJ5KGdnbmV0d29yaykKbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHJhbmRvbWNvbG9SKQpsaWJyYXJ5KHN0cmluZ2kpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KGdncmFwaCkKbGlicmFyeShncmFwaGxheW91dHMpCmxpYnJhcnkodmlzTmV0d29yaykKYGBgCiMgTmV0d29yayB2aXN1YWxpemF0aW9uIHVzaW5nIG91dHB1dCBmcm9tIHRleHQgbW9kZWwKIyMgRGF0YSBwcmVwYXJhdGlvbgpgYGB7ciBpbXBvcnQgZGF0YSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CmVkZ2VsaXN0IDwtIHJlYWQuY3N2KCIuLi8uLi8uLi9EYXRhL1RleHRfTW9kZWxfRGF0YS9lZGdlbGlzdC5jc3YiKQplZGdlbGlzdApgYGAKSW5kaWNhdG9yIHRpdGxlCmBgYHtyLCB0ZXh0IHRpdGxlcywgZWNobz1UUlVFLCBldmFsPVRSVUV9CmluZGljYXRvcl9pbmZvIDwtIHJlYWQuY3N2KCIuLi8uLi8uLi9EYXRhL1RleHRfTW9kZWxfRGF0YS9pbmRpY2F0b3JfYXR0LmNzdiIpCmxpYnJhcnkoc3RyaW5ncikKc3RyX3JlcGxhY2VfYWxsKGluZGljYXRvcl9pbmZvJEluZGljYXRvciwgZml4ZWQoIiAiKSwgIiIpClRleHRkYXRhIDwtIGRhdGF0YWJsZShpbmRpY2F0b3JfaW5mbywgcm93bmFtZXM9VFJVRSwgY2FwdGlvbj1odG1sdG9vbHM6OnRhZ3MkY2FwdGlvbihzdHlsZT0iY2FwdGlvbi1zaWRlOiBib3R0b207IHRleHQtYWxpZ246IGNlbnRlcjsiLCAiSW5ub3ZhdGl2ZSBjb3VudGllcyBpbiB0aGUgVS5TLiIpLCBmaWx0ZXI9InRvcCIsIGV4dGVuc2lvbnM9IkJ1dHRvbnMiLCBvcHRpb25zPWxpc3QoZG9tID0gIkJmcnRpcCIsIGJ1dHRvbnMgPSBjKCJjb2x2aXMiLCAiY29weSIsICJjc3YiLCAiZXhjZWwiLCAicGRmIiwgInByaW50IikpKQpUZXh0ZGF0YQpgYGAKRm9yIGZ1dHVyZSBjbGFzc2lmaWNhdGlvbiBvZiBpbmRpY2F0b3JzIGludG8gdGhlIGdvYWxzIHRoZXkgYmVsb25nIHRvLCBjcmVhdGUgdGhlIG5vZGVzIGRhdGFmcmFtZToKYGBge3IgY3JlYXRlIG5vZGVzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0Kbm9kZXMgPC0gZWRnZWxpc3QgJT4lCiAgc2VsZWN0KGluZGljYXRvciwgcmVsYXRlZF9pbmRpY2F0b3IpCm5vZGVzIDwtIGRhdGEuZnJhbWUoSW5kaWNhdG9yID0gdW5saXN0KG5vZGVzLCB1c2UubmFtZXMgPSBGQUxTRSkpCm5vZGVzIDwtIGRpc3RpbmN0KG5vZGVzKQpzdHJfcmVwbGFjZV9hbGwobm9kZXMkSW5kaWNhdG9yLCBmaXhlZCgiICIpLCAiIikKI25vZGVzJGdvYWwgPC0gc3RyaV9tYXRjaF9maXJzdF9yZWdleChub2RlcyRpbmRpY2F0b3IsICIoLio/KVxcLiIpWywyXQojbm9kZXMkZ29hbCA8LWFzLm51bWVyaWMobm9kZXMkZ29hbCkKbm9kZXM8LW1lcmdlKHg9bm9kZXMseT1pbmRpY2F0b3JfaW5mbyxieT0iSW5kaWNhdG9yIixhbGwueD1UUlVFKQpnPC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoZWRnZWxpc3QsIGRpcmVjdGVkPUZBTFNFLCB2ZXJ0aWNlcz1ub2RlcykKaW5fZGVncmVlPC1kZWdyZWUoZywgbW9kZT0iaW4iKQppbl9kZWdyZWU8LWFzLmRhdGEuZnJhbWUoaW5fZGVncmVlKQppbl9kZWdyZWUgPC0gY2JpbmQocm93bmFtZXMoaW5fZGVncmVlKSwgaW5fZGVncmVlKQpyb3duYW1lcyhpbl9kZWdyZWUpIDwtIE5VTEwKY29sbmFtZXMoaW5fZGVncmVlKSA8LSBjKCJJbmRpY2F0b3IiLCJpbl9kZWdyZWUiKQpzdHJfcmVwbGFjZV9hbGwoaW5fZGVncmVlJEluZGljYXRvciwgZml4ZWQoIiAiKSwgIiIpCm5vZGVzPC1tZXJnZSh4PW5vZGVzLHk9aW5fZGVncmVlLGJ5PSJJbmRpY2F0b3IiLGFsbC54PVRSVUUpCm5vZGVzPC1ub2RlcyAlPiUKICBzZWxlY3QoSW5kaWNhdG9yLCBHb2FsLCBJbmRpY2F0b3JfdGl0bGUsIGluX2RlZ3JlZSkKbm9kZXMKYGBgCiMjIFZpc3VhbGl6YXRpb24KSW4gdGhlIG5ldHdvcmsgZ3JhcGggYmVsb3csIHRoZSBzaXplIG9mIGVhY2ggdmVydGljZXMgKGVhY2ggaW5kaWNhdG9yKSByZXByZXNlbnRzIHRoZSBudW1iZXIgb2YgcmVsYXRlZCBpbmRpY2F0b3JzIHRoYXQgYXJlIGNvbm5lY3RlZCB0byBpdC4gVGhlIHdpZHRoIG9mIHRoZSBlZGdlcyBsaW5raW5nIGVhY2ggaW5kaWNhdG9yIGlzIGRldGVybWluZWQgYWNjb3JkaW5nIHRvIHRoZSBzaW1pbGFyaXR5IHNjb3JlIGJldHdlZW4gZWFjaCBwYWlyIG9mIHJlbGF0ZWQgaW5kaWNhdG9ycy4gVGhlIGluZGljYXRvcnMgYXJlIGdyb3VwZWQgYWNjb3JkaW5nIHRvIHRoZSBnb2FscyB0aGV5IGJlbG9uZyB0bywgd2hpY2ggYXJlIGRlbm90ZWQgYnkgZGlmZmVyZW50IGNvbG9ycyBvZiB0aGUgdmVydGljZXMuCmBgYHtyIFN0YXRpYyBuZXR3b3JrIGZyb20gdGV4dCwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTE1LCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpnPC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoZWRnZWxpc3QsIGRpcmVjdGVkPUZBTFNFLCB2ZXJ0aWNlcz1ub2RlcykKI0FkZCBhdHRyaWJ1dGVzCkUoZykkd2VpZ2h0PC1FKGcpJHNpbWlsYXJpdHlfc2NvcmUKVihnKSRpbl9kZWdyZWU8LWRlZ3JlZShnLCBtb2RlPSJpbiIpCmNvbHJzPC1jKCIjZWExZDJkIiwgIiNkMTlmMmEiLCIjMmQ5YTQ3IiwgIiNjMjIwMzMiLCIjZWY0MTJhIiwgIiMwMGFkZDkiLCAiI2ZkYjcxNCIsICIjOGYxODM4IiwgIiNmMzZlMjQiLCAiI2UwMWE4MyIsICIjZjk5ZDI1IiwgIiNjZDhiMmEiLCAiIzQ4NzczYyIsICIjMDA3ZGJiIiwgIiM0MGFlNDkiLCAgIiMwMDU1OGEiLCAiIzFhMzY2OCIpClYoZykkY29sb3I8LWNvbHJzW1YoZykkR29hbF0KI1Bsb3QgZ3JhcGgKcGxvdChnLCB2ZXJ0ZXgubGFiZWw9TkEsIGVkZ2UuY29sb3I9ImdyYXk3NyIsIHZlcnRleC5jb2xvcj1WKGcpJGNvbG9yLCB2ZXJ0ZXguc2l6ZT1WKGcpJGluX2RlZ3JlZSwgZWRnZS53aWR0aD1FKGcpJHdlaWdodCoxMCwgbGF5b3V0PWxheW91dF9uaWNlbHkoZykpCnBsb3QoZywgdmVydGV4LmxhYmVsLmNvbG9yPSJibGFjayIsIHZlcnRleC5sYWJlbC5jZXg9Mi41LCBlZGdlLmNvbG9yPSJncmF5NzciLCB2ZXJ0ZXguY29sb3I9VihnKSRjb2xvciwgdmVydGV4LnNpemU9VihnKSRpbl9kZWdyZWUsIGVkZ2Uud2lkdGg9RShnKSR3ZWlnaHQqMTAsIGxheW91dD1sYXlvdXRfbmljZWx5KGcpKQojbGVnZW5kKHg9LTExLCB5PS0xMSwgYygiR29hbCAxIiwiR29hbCAyIiwiR29hbCAzIiwiR29hbCA0IiwiR29hbCA1IiwiR29hbCA2IiwiR29hbCA3IiwiR29hbCA4IiwiR29hbCA5IiwiR29hbCAxMCIsIkdvYWwgMTEiLCAiR29hbCAxMiIsIkdvYWwgMTMiLCAiR29hbCAxNCIsICJHb2FsIDE1IiwgIkdvYWwgMTYiLCAiR29hbCAxNyIpLCBwY2g9MjAsIGNvbD0iIzc3Nzc3NyIsIHB0LmJnPWNvbHJzLCBwdC5jZXg9MiwgY2V4PS44LCBidHk9Im4iLCBuY29sPTEpCmBgYAoKYGBge3IsIEludGVyYWN0aXZlIFRleHQgTmV0d29yayBDb25uaWUsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQoKZWRnZXMgPC0gZWRnZWxpc3QgJT4lIGRwbHlyOjpyZW5hbWUoSW5kaWNhdG9yID0gaW5kaWNhdG9yKQoKbm9kZXMgPC0gZGF0YS5mcmFtZShpZCA9IG5vZGVzJEluZGljYXRvciwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IG5vZGVzJEluZGljYXRvciwKICAgICAgICAgICAgICAgICAgICBncm91cCA9IG5vZGVzJEdvYWwsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBpZmVsc2Uobm9kZXMkR29hbCA9PSAxLCIjZWExZDJkIixpZmVsc2Uobm9kZXMkR29hbCA9PSAyLCIjZDE5ZjJhIixpZmVsc2Uobm9kZXMkR29hbCA9PSAzLCIjMmQ5YTQ3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDQsIiNjMjIwMzMiLGlmZWxzZShub2RlcyRHb2FsID09IDUsIiNlZjQxMmEiLGlmZWxzZShub2RlcyRHb2FsID09IDYsIiMwMGFkZDgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5vZGVzJEdvYWwgPT0gNywiI2ZkYjcxNCIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gOCwiIzhmMTgzOCIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gOSwiI2YzNmUyNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uobm9kZXMkR29hbCA9PSAxMCwiI2UwMWE4MyIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTEsIiNmOTlkMjUiLGlmZWxzZShub2RlcyRHb2FsID09IDEyLCIjY2Q4YjJhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDEzLCIjNDg3NzNjIixpZmVsc2Uobm9kZXMkR29hbCA9PSAxNCwiIzAwN2RiYiIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTUsIiM0MGFlNDkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTYsIiMwMDU1OGEiLCIjMWEzNjY4IikpKSkpKSkpKSkpKSkpKSksCiAgICAgICAgICAgICAgICAgICAgaGlnaGxpZ2h0ID0gaWZlbHNlKG5vZGVzJEdvYWwgPT0gMSwiI2VhMWQyZCIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMiwiI2QxOWYyYSIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMywiIzJkOWE0NyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uobm9kZXMkR29hbCA9PSA0LCIjYzIyMDMzIixpZmVsc2Uobm9kZXMkR29hbCA9PSA1LCIjZWY0MTJhIixpZmVsc2Uobm9kZXMkR29hbCA9PSA2LCIjMDBhZGQ4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDcsIiNmZGI3MTQiLGlmZWxzZShub2RlcyRHb2FsID09IDgsIiM4ZjE4MzgiLGlmZWxzZShub2RlcyRHb2FsID09IDksIiNmMzZlMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTAsIiNlMDFhODMiLGlmZWxzZShub2RlcyRHb2FsID09IDExLCIjZjk5ZDI1IixpZmVsc2Uobm9kZXMkR29hbCA9PSAxMiwiI2NkOGIyYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uobm9kZXMkR29hbCA9PSAxMywiIzQ4NzczYyIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTQsIiMwMDdkYmIiLGlmZWxzZShub2RlcyRHb2FsID09IDE1LCIjNDBhZTQ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDE2LCIjMDA1NThhIiwiIzFhMzY2OCIpKSkpKSkpKSkpKSkpKSkpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSBub2RlcyRpbl9kZWdyZWUqMTApCgplZGdlcyA8LSBkYXRhLmZyYW1lKGZyb20gPSBlZGdlcyRJbmRpY2F0b3IsIHRvPWVkZ2VzJHJlbGF0ZWRfaW5kaWNhdG9yLCB3aWR0aCA9IGVkZ2VzJHNpbWlsYXJpdHlfc2NvcmUqNCwgY29sb3I9J2dyYXknKQoKbm9kZXMkc2hhcGUgIDwtICJkb3QiICAKbm9kZXMkc2hhZG93IDwtIEZBTFNFCgojIHRoaXMgc2VjdGlvbiBkb2Vzbid0IGFsbG93IG91ciBncmFwaCB0byBzaG93IHVwIC0gbm8gaWRlYSB3aHkuIAojIG5vZGVzJGNvbG9yLmJhY2tncm91bmQgPC0gbm9kZXMkY29sb3IgCiMgbm9kZXMkY29sb3IuYm9yZGVyIDwtIG5vZGVzJGNvbG9yIAojIG5vZGVzJGNvbG9yLmhpZ2hsaWdodC5iYWNrZ3JvdW5kIDwtIG5vZGVzJGNvbG9yIAojIG5vZGVzJGNvbG9yLmhpZ2hsaWdodC5ib3JkZXIgPC0gbm9kZXMkY29sb3IgCgoKZWRnZXMkY29sb3IgPC0gImdyYXkiICAgICMgbGluZSBjb2xvciAgCmVkZ2VzJHNtb290aCA8LSBGQUxTRSAgICAjIHNob3VsZCB0aGUgZWRnZXMgYmUgY3VydmVkPwplZGdlcyRzaGFkb3cgPC0gRkFMU0UKCnZpc25ldDwtdmlzTmV0d29yayhub2RlcyxlZGdlcywgaGVpZ2h0ID0gIjcwMHB4Iiwgd2lkdGggPSAiMTAwJSIsIG1haW49IlRleHQgTmV0d29yayBNb2RlbCIsc3VibWFpbj0gIlVOIFNERyBJbmRpY2F0b3IgTWV0YWRhdGEiLCBmb290ZXI9Ilpvb20gaW4gdG8gc2VlIGluZGljYXRvciBuYW1lLCBjbGljay9ob3ZlciB0byBzZWUgaW5kaWNhdG9yIHRpdGxlIikgJT4lCiAgICB2aXNFZGdlcyhzbW9vdGggPSBGQUxTRSkgJT4lCgogIHZpc09wdGlvbnMoc2VsZWN0ZWRCeSA9ICJHb2FsIiwgCiAgICAgICAgICAgICBoaWdobGlnaHROZWFyZXN0ID0gVFJVRSwgCiAgICAgICAgICAgICBub2Rlc0lkU2VsZWN0aW9uID0gVFJVRSkgIyU+JQogICN2aXNMZWdlbmQobWFpbj0iTGVnZW5kIixwb3NpdGlvbj0icmlnaHQiLCBuY29sPTEpCnZpc25ldAp2aXNTYXZlKHZpc25ldCwgZmlsZSA9ICJUZXh0IE5ldHdvcmsgTW9kZWwuaHRtbCIpCmBgYAojIE5ldHdvcmsgdmlzdWFsaXphdGlvbiB1c2luZyBvdXRwdXQgZnJvbSB0aGUgc29jaWFsIG5ldHdvcmsgbW9kZWwKIyMgSW5kb25lc2lhCiMjI0RhdGEgcHJlcGFyYXRpb24KYGBge3IgaW1wb3J0IEluZG9uZXNpYSBuZXR3b3JrIGNvZWZmaWNpZW50cywgZWNobz1UUlVFLCBldmFsPVRSVUV9CmVkZ2VsaXN0aW5kbyA8LSByZWFkLmNzdigifi9Eb2N1bWVudHMvR2l0SHViL0c1MDU1X1ByYWN0aWN1bV9Qcm9qZWN0Mi9EYXRhL1BDQV9yZXN1bHRzL2luZG9fY29lZmZpY2llbnRzX3NpZy5jc3YiKQojU29tZSBwcmVwcm9jZXNzaW5nCmVkZ2VsaXN0aW5kbzwtZWRnZWxpc3RpbmRvJT4lCiAgc2VsZWN0KFZhcjEsIFZhcjIsIHZhbHVlKSU+JQogIGZpbHRlcihWYXIxIT1WYXIyKQpuYW1lcyhlZGdlbGlzdGluZG8pPC1jKCJmcm9tIiwidG8iLCJ2YWx1ZSIpCmVkZ2VsaXN0aW5kbwpgYGAKRm9yIGZ1dHVyZSBjbGFzc2lmaWNhdGlvbiBvZiBpbmRpY2F0b3JzIGludG8gdGhlIGdvYWxzIHRoZXkgYmVsb25nIHRvLCBjcmVhdGUgdGhlIG5vZGVzIGRhdGFmcmFtZToKYGBge3IgSW5kb25lc2lhIG5vZGVzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KaW5kb25vZGVzIDwtIGVkZ2VsaXN0aW5kbyAlPiUKICBzZWxlY3QoZnJvbSwgdG8pCmluZG9ub2RlcyA8LSBkYXRhLmZyYW1lKEluZGljYXRvciA9IHVubGlzdChpbmRvbm9kZXMsIHVzZS5uYW1lcyA9IEZBTFNFKSkKaW5kb25vZGVzIDwtIGRpc3RpbmN0KGluZG9ub2RlcykKI2luZG9ub2RlcyRnb2FsIDwtIHN0cmlfbWF0Y2hfZmlyc3RfcmVnZXgoaW5kb25vZGVzJGluZGljYXRvciwgIiguKj8pXFwuIilbLDJdCiNpbmRvbm9kZXMkZ29hbCA8LWFzLm51bWVyaWMoaW5kb25vZGVzJGdvYWwpCmluZG9ub2RlczwtbWVyZ2UoeD1pbmRvbm9kZXMseT1pbmRpY2F0b3JfaW5mbyxieT0iSW5kaWNhdG9yIixhbGwueD1UUlVFKQpnMjwtZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGVkZ2VsaXN0aW5kbywgZGlyZWN0ZWQ9RkFMU0UsIHZlcnRpY2VzPWluZG9ub2RlcykKaW5fZGVncmVlPC1kZWdyZWUoZzIsIG1vZGU9ImluIikKaW5fZGVncmVlPC1hcy5kYXRhLmZyYW1lKGluX2RlZ3JlZSkKaW5fZGVncmVlIDwtIGNiaW5kKHJvd25hbWVzKGluX2RlZ3JlZSksIGluX2RlZ3JlZSkKcm93bmFtZXMoaW5fZGVncmVlKSA8LSBOVUxMCmNvbG5hbWVzKGluX2RlZ3JlZSkgPC0gYygiSW5kaWNhdG9yIiwiaW5fZGVncmVlIikKaW5kb25vZGVzPC1tZXJnZSh4PWluZG9ub2Rlcyx5PWluX2RlZ3JlZSxieT0iSW5kaWNhdG9yIixhbGwueD1UUlVFKQppbmRvbm9kZXM8LWluZG9ub2RlcyAlPiUKICBhcnJhbmdlKEdvYWwpCmluZG9ub2RlczwtaW5kb25vZGVzICU+JQogIHNlbGVjdChJbmRpY2F0b3IsIEdvYWwsIEluZGljYXRvcl90aXRsZSwgaW5fZGVncmVlKQppbmRvbm9kZXMKaW5kb25vZGVzCmBgYAojIyMgVmlzdWFsaXphdGlvbgpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUUsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0KdmlzLm5vZGVzIDwtIGluZG9ub2Rlcwp2aXMubGlua3MgPC0gZWRnZWxpc3RpbmRvCnZpcy5ub2RlcyRzaGFwZSAgPC0gImRvdCIgIAp2aXMubm9kZXMkc2hhZG93IDwtIEZBTFNFICMgTm9kZXMgd2lsbCBkcm9wIHNoYWRvdwp2aXMubm9kZXMkdGl0bGUgIDwtIHZpcy5ub2RlcyRJbmRpY2F0b3JfdGl0bGUgIyBUZXh0IG9uIGNsaWNrCnZpcy5ub2RlcyRsYWJlbCAgPC0gdmlzLm5vZGVzJEluZGljYXRvciAjIE5vZGUgbGFiZWwKdmlzLm5vZGVzJHNpemUgICA8LSB2aXMubm9kZXMkaW5fZGVncmVlICMgTm9kZSBzaXplCiN2aXMubm9kZXMkZ3JvdXAgPC0gdmlzLm5vZGVzJEdvYWwKdmlzLm5vZGVzJGNvbG9yLmJhY2tncm91bmQgPC0gYygiI2VhMWQyZCIsICIjZDE5ZjJhIiwiIzJkOWE0NyIsICIjYzIyMDMzIiwiI2VmNDEyYSIsICIjMDBhZGQ5IiwgIiNmZGI3MTQiLCAiIzhmMTgzOCIsICIjZjM2ZTI0IiwgIiNlMDFhODMiLCAiI2Y5OWQyNSIsICIjY2Q4YjJhIiwgIiM0ODc3M2MiLCAiIzAwN2RiYiIsICIjNDBhZTQ5IiwgICIjMDA1NThhIiwgIiMxYTM2NjgiKVt2aXMubm9kZXMkR29hbF0KdmlzLm5vZGVzJGNvbG9yLmJvcmRlciA8LSBjKCIjZWExZDJkIiwgIiNkMTlmMmEiLCIjMmQ5YTQ3IiwgIiNjMjIwMzMiLCIjZWY0MTJhIiwgIiMwMGFkZDkiLCAiI2ZkYjcxNCIsICIjOGYxODM4IiwgIiNmMzZlMjQiLCAiI2UwMWE4MyIsICIjZjk5ZDI1IiwgIiNjZDhiMmEiLCAiIzQ4NzczYyIsICIjMDA3ZGJiIiwgIiM0MGFlNDkiLCAgIiMwMDU1OGEiLCAiIzFhMzY2OCIpW3Zpcy5ub2RlcyRHb2FsXQp2aXMubm9kZXMkY29sb3IuaGlnaGxpZ2h0LmJhY2tncm91bmQgPC0gYygiI2VhMWQyZCIsICIjZDE5ZjJhIiwiIzJkOWE0NyIsICIjYzIyMDMzIiwiI2VmNDEyYSIsICIjMDBhZGQ5IiwgIiNmZGI3MTQiLCAiIzhmMTgzOCIsICIjZjM2ZTI0IiwgIiNlMDFhODMiLCAiI2Y5OWQyNSIsICIjY2Q4YjJhIiwgIiM0ODc3M2MiLCAiIzAwN2RiYiIsICIjNDBhZTQ5IiwgICIjMDA1NThhIiwgIiMxYTM2NjgiKVt2aXMubm9kZXMkR29hbF0KdmlzLm5vZGVzJGNvbG9yLmhpZ2hsaWdodC5ib3JkZXIgPC0gYygiI2VhMWQyZCIsICIjZDE5ZjJhIiwiIzJkOWE0NyIsICIjYzIyMDMzIiwiI2VmNDEyYSIsICIjMDBhZGQ5IiwgIiNmZGI3MTQiLCAiIzhmMTgzOCIsICIjZjM2ZTI0IiwgIiNlMDFhODMiLCAiI2Y5OWQyNSIsICIjY2Q4YjJhIiwgIiM0ODc3M2MiLCAiIzAwN2RiYiIsICIjNDBhZTQ5IiwgICIjMDA1NThhIiwgIiMxYTM2NjgiKVt2aXMubm9kZXMkR29hbF0KdmlzLmxpbmtzJHdpZHRoIDwtIHZpcy5saW5rcyR2YWx1ZSoxMDAgIyBsaW5lIHdpZHRoCnZpcy5saW5rcyRjb2xvciA8LSAiZ3JheSIgICAgIyBsaW5lIGNvbG9yICAKI3Zpcy5saW5rcyRhcnJvd3MgPC0gIm1pZGRsZSIgIyBhcnJvd3M6ICdmcm9tJywgJ3RvJywgb3IgJ21pZGRsZScKdmlzLmxpbmtzJHNtb290aCA8LSBGQUxTRSAgICAjIHNob3VsZCB0aGUgZWRnZXMgYmUgY3VydmVkPwp2aXMubGlua3Mkc2hhZG93IDwtIEZBTFNFIAp2aXNuZXQ8LXZpc05ldHdvcmsodmlzLm5vZGVzLHZpcy5saW5rcywgaGVpZ2h0ID0gIjcwMHB4Iiwgd2lkdGggPSAiMTAwJSIsIG1haW49IlNvY2lhbCBOZXR3b3JrIE1vZGVsLUluZG9uZXNpYSIsIHN1Ym1haW49IlVOIFNERyBJbmRpY2F0b3IgRGF0YWJhc2UiLGZvb3Rlcj0gIlpvb20gaW4gdG8gc2VlIGluZGljYXRvciBuYW1lLCBjbGljayBvciBob3ZlciB0byBzZWUgaW5kaWNhdG9yIHRpdGxlIikgJT4lCiAgdmlzT3B0aW9ucyhzZWxlY3RlZEJ5ID0gIkdvYWwiLCAKICAgICAgICAgICAgIGhpZ2hsaWdodE5lYXJlc3QgPSBUUlVFLCAKICAgICAgICAgICAgIG5vZGVzSWRTZWxlY3Rpb24gPSBUUlVFKSAjJT4lCiAgI3Zpc0xlZ2VuZChtYWluPSJMZWdlbmQiLCBwb3NpdGlvbj0icmlnaHQiLCBuY29sPTEpCnZpc25ldAp2aXNTYXZlKHZpc25ldCwgZmlsZSA9ICJTb2NpYWwgTmV0d29yayBNb2RlbC1JbmRvbmVzaWEuaHRtbCIpCmBgYAoKIyMgR3VhdGVtYWxhIChOb3QgZmluaXNoZWQpCiMjIyBEYXRhIHByZXBhcmF0aW9uCmBgYHtyIGltcG9ydCBHdWF0ZW1hbGEgbmV0d29yayBjb2VmZmljaWVudHMsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQplZGdlbGlzdGd1YXRlIDwtIHJlYWQuY3N2KCJ+L0RvY3VtZW50cy9HaXRIdWIvRzUwNTVfUHJhY3RpY3VtX1Byb2plY3QyL0RhdGEvUENBX3Jlc3VsdHMvZ3VhX2NvZWZmaWNpZW50c19zaWcuY3N2IikKI1NvbWUgcHJlcHJvY2Vzc2luZwplZGdlbGlzdGd1YXRlPC1lZGdlbGlzdGd1YXRlJT4lCiAgc2VsZWN0KFZhcjEsIFZhcjIsIHZhbHVlKSU+JQogIGZpbHRlcihWYXIxIT1WYXIyKQpuYW1lcyhlZGdlbGlzdGluZG8pPC1jKCJmcm9tIiwidG8iLCJ2YWx1ZSIpCmVkZ2VsaXN0Z3VhdGUKYGBgCiMjIyBWaXN1YWxpemF0aW9uCmBgYHtyIEd1YXRlbWFsYSBub2RlcywgZWNobz1UUlVFLCBldmFsPVRSVUV9Cmd1YXRlbm9kZXMgPC0gZWRnZWxpc3RndWF0ZSAlPiUKICBzZWxlY3QoVmFyMSwgVmFyMikKZ3VhdGVub2RlcyA8LSBkYXRhLmZyYW1lKGluZGljYXRvcm5hbWUgPSB1bmxpc3QoZ3VhdGVub2RlcywgdXNlLm5hbWVzID0gRkFMU0UpKQpndWF0ZW5vZGVzIDwtIGRpc3RpbmN0KGd1YXRlbm9kZXMpCiNndWF0ZW5vZGVzJGdvYWwgPC0gc3RyaV9tYXRjaF9maXJzdF9yZWdleChndWF0ZW5vZGVzJGluZGljYXRvciwgIiguKj8pXFwuIilbLDJdCiNndWF0ZW5vZGVzJGdvYWwgPC1hcy5udW1lcmljKGd1YXRlbm9kZXMkZ29hbCkKZzM8LWdyYXBoX2Zyb21fZGF0YV9mcmFtZShlZGdlbGlzdGd1YXRlLCBkaXJlY3RlZD1GQUxTRSwgdmVydGljZXM9Z3VhdGVub2RlcykKZ3VhdGVub2RlcwpgYGAK